package view;

import controller.*;

import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.text.*;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class ChatServer {
    private final JTextPane contentArea;
    private final JTextField txt_message;
    public DefaultListModel<String> listModel;
    public JList<String> userList;
    private final JTextArea fileTextArea;
    private final Charset charset = StandardCharsets.UTF_8; // 字符集
    private final ByteBuffer buffer = ByteBuffer.allocate(1024); // 缓存
    public final static Map<String, SocketChannel> onlineUsers = new ConcurrentHashMap<>(); // 将用户对应的channel对应起来
    DefaultListModel<String> fileModel;
    private Selector selector;
    private String selectedValue;
    private String fileSelectedValue;
    private final MessageController controller = new MessageController();
    private ServerSocketChannel server;
    private final JFrame frame;
    private volatile boolean flag = true;
    public static boolean flag2 = true;
    // 存储链接文本和文件路径的映射
    DefaultListModel<String> groupModel;
    JList<String> groupList;
    public static final Map<String, String> links = new HashMap<>();
    private final MainMessageController messageController = new MainMessageController();
    private final GroupChatController groupChatController = new GroupChatController();
    private final GroupMessageController groupMessageController = new GroupMessageController();
    private final SilenceUserController silenceUserController = new SilenceUserController();

    public ChatServer() {
        frame = new JFrame("服务器");
        frame.setIconImage(Toolkit.getDefaultToolkit().createImage(ChatServer.class.getResource("qq.jpg")));
        contentArea = new JTextPane();
        String[] allGroupNames = groupChatController.getAllGroupNames();
        groupModel = new DefaultListModel<>();
        for (String groupName : allGroupNames) {
            groupModel.addElement(groupName);
        }
        groupList = new JList<>(groupModel);
        contentArea.setEditable(false);
        txt_message = new JTextField();
        JButton btn_send = new JButton("发送");
        JButton btn_user = new JButton("管理用户");
        JButton btn_group = new JButton("群聊管理");
        listModel = new DefaultListModel<>();
        userList = new JList<>(listModel);
        JButton btn_file = new JButton("文件");
        JButton btn_flush = new JButton("刷新");
        JButton btn_repair = new JButton("解除禁言");
        JPanel southPanel = new JPanel(new BorderLayout());
        southPanel.setBorder(new TitledBorder("写消息"));
        southPanel.add(txt_message, BorderLayout.CENTER);
        JPanel jPanel = new JPanel(new FlowLayout());
        jPanel.add(btn_file);
        jPanel.add(btn_send);
        southPanel.add(jPanel, BorderLayout.EAST);
        JScrollPane leftPanel1 = new JScrollPane(userList);
        JPanel leftPanel = new JPanel(new BorderLayout());
        leftPanel.add(leftPanel1, BorderLayout.NORTH);
        JScrollPane leftPanel2 = new JScrollPane(groupList);
        leftPanel2.setBorder(new TitledBorder("群聊"));
        leftPanel.add(leftPanel2, BorderLayout.CENTER);
        JPanel btnPanel = new JPanel(new GridLayout(2, 1));
        JButton button2 = new JButton("禁言");
        JButton button = new JButton("强制下线");
        btnPanel.add(button2);
        btnPanel.add(button);
        JButton button1 = new JButton("取消选择");
        JTextArea textArea = new JTextArea();
        textArea.setEditable(false);
        JPanel buttonPanel = new JPanel(new BorderLayout());
        buttonPanel.add(btnPanel, BorderLayout.SOUTH);
        buttonPanel.add(textArea, BorderLayout.CENTER);
        buttonPanel.add(button1, BorderLayout.NORTH);
        leftPanel.add(buttonPanel, BorderLayout.SOUTH);
        leftPanel1.setBorder(new TitledBorder("在线用户"));
        JScrollPane rightPanel = new JScrollPane(contentArea);
        rightPanel.setBorder(new TitledBorder("消息显示区"));
        JSplitPane centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, rightPanel);
        centerSplit.setDividerLocation(100);
        JPanel northPanel = new JPanel();
        northPanel.setLayout(new GridLayout(1, 6));
        northPanel.add(btn_user);
        northPanel.add(btn_group);
        northPanel.add(btn_repair);
        northPanel.add(btn_flush);
        northPanel.setBorder(new TitledBorder("配置信息"));
        JPanel eastPanel = new JPanel(new BorderLayout());
        String[] messages = messageController.getMessages();
        fileModel = new DefaultListModel<>();
        for (String s : messages) {
            String[] parts = s.split(":");
            if (parts.length == 4) {
                fileModel.addElement(parts[1] + ":" + parts[2]);
            }
        }
        JList<String> jList = new JList<>(fileModel);
        jList.setCellRenderer(new DefaultListCellRenderer() {
            @Override
            public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
                JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
                label.setPreferredSize(new Dimension(200, label.getPreferredSize().height)); // 设置固定宽度 200
                return label;
            }
        });
        JScrollPane jScrollPane = new JScrollPane(jList);
        jScrollPane.setBorder(new TitledBorder("文件"));
        JPanel jPanel1 = new JPanel(new BorderLayout());
        fileTextArea = new JTextArea();
        fileTextArea.setEditable(false);
        fileTextArea.setLineWrap(true);
        JLabel jLabel = new JLabel("你选择的文件是：");
        JButton btn_config = new JButton("查看");
        jPanel1.add(jLabel, BorderLayout.NORTH);
        jPanel1.add(fileTextArea, BorderLayout.CENTER);
        jPanel1.add(btn_config, BorderLayout.SOUTH);
        eastPanel.add(jPanel1, BorderLayout.SOUTH);
        eastPanel.add(jScrollPane, BorderLayout.CENTER);
        frame.setLayout(new BorderLayout());
        frame.add(northPanel, BorderLayout.NORTH);
        frame.add(eastPanel, BorderLayout.EAST);
        frame.add(centerSplit, BorderLayout.CENTER);
        frame.add(southPanel, BorderLayout.SOUTH);
        frame.setSize(800, 600);
        int screen_width = Toolkit.getDefaultToolkit().getScreenSize().width;
        int screen_height = Toolkit.getDefaultToolkit().getScreenSize().height;
        frame.setLocation((screen_width - frame.getWidth()) / 2, (screen_height - frame.getHeight()) / 2);
        frame.setVisible(true);
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                frame.dispose();
                flag2 = false;
                stopServer();
                AdministratorView.flag = true;
            }
        });
        btn_config.addActionListener(e -> {
            if (fileSelectedValue != null) {
                openFile();
            } else {
                JOptionPane.showMessageDialog(null, "未选择文件");
            }
        });
        btn_flush.addActionListener(e -> {
            updateGroupList();
            updateFileList();
        });
        btn_group.addActionListener(e -> {
            GroupView groupView = new GroupView();
            groupView.showUi();
        });
        btn_repair.addActionListener(e -> {
            UnbanUserView unbanUserView = new UnbanUserView();
            unbanUserView.showUi();
        });
        button2.addActionListener(e -> {
            if (selectedValue != null) {
                boolean b = silenceUserController.silenceUser(selectedValue);
                if (b) {
                    JOptionPane.showMessageDialog(null, selectedValue + "被禁言了");
                } else {
                    JOptionPane.showMessageDialog(null, selectedValue + "已被禁言");
                }
            }
        });
        btn_user.addActionListener(e -> {
            ManageUsersView manageUsersView = new ManageUsersView();
            manageUsersView.showUi();
        });
        button.addActionListener(e -> {
            String s = selectedValue;
            try {
                downLoad(s);
            } catch (Exception ex) {
                JOptionPane.showMessageDialog(null, "未选择强制下线用户");
            }
        });
        startServer();
        btn_send.addActionListener(e -> sendMessage(txt_message.getText().trim()));
        // 文本框回车事件监听
        txt_message.addActionListener(e -> {
            sendMessage(txt_message.getText().trim());
            txt_message.setText("");
        });
        btn_file.addActionListener(e -> {
            // 创建 JFileChooser 对象
            JFileChooser fileChooser = new JFileChooser();
            // 设置默认目录
            fileChooser.setCurrentDirectory(new File(System.getProperty("user.home")));
            // 打开文件选择对话框
            int result = fileChooser.showOpenDialog(null);
            // 判断用户是否选择了一个文件
            if (result == JFileChooser.APPROVE_OPTION) {
                File selectedFile = fileChooser.getSelectedFile();
                String path = selectedFile.getAbsolutePath();
                JOptionPane.showMessageDialog(frame, "选择的文件: " + path);
                String string = "服务器:" + selectedFile + ":" + "1";
                appendMessage(string);
                try {
                    broadCast(string);
                } catch (IOException ex) {
                    appendMessage("发送消息失败");
                }
                links.put(path, path);
                messageController.addMessage("服务器", path, 1);
            } else {
                JOptionPane.showMessageDialog(frame, "未选择文件");
            }
            updateFileList();
        });
        userList.addListSelectionListener(e -> {
            selectedValue = userList.getSelectedValue();
            textArea.setText(selectedValue);
        });
        jList.addListSelectionListener(e -> {
            fileSelectedValue = jList.getSelectedValue();
            fileTextArea.setText(fileSelectedValue);
        });
        button1.addActionListener(e -> updateUserList());
        contentArea.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                try {
                    contentArea.viewToModel2D(e.getPoint());
                    String clickedLink = findClickedLink(contentArea, e.getPoint());
                    if (clickedLink != null) {
                        String fileName = links.get(clickedLink);
                        File file = new File(fileName);
                        if (file.exists()) {
                            Desktop.getDesktop().open(file);
                        } else {
                            JOptionPane.showMessageDialog(frame, "文件不存在: " + file.getAbsolutePath());
                        }
                    }
                } catch (BadLocationException | IOException ex) {
                    JOptionPane.showMessageDialog(frame, "错误: " + ex.getMessage());
                }
            }
        });
    }

    private void stopClients() {
        Set<String> keys = new HashSet<>(onlineUsers.keySet());
        for (String key : keys) {
            downLoad(key);
        }
        JOptionPane.showMessageDialog(null, "服务器断开连接");
    }

    private void stopServer() {
        flag = false;
        stopClients();
        if (selector != null) {
            selector.wakeup(); // 唤醒阻塞中的 select()
            try {
                for (SelectionKey key : selector.keys()) {
                    Channel channel = key.channel();
                    if (channel != null && channel.isOpen()) {
                        channel.close();
                    }
                }
            } catch (IOException e) {
                appendMessage("关闭通道失败！");
            }
            try {
                selector.close(); // 关闭选择器
            } catch (IOException e) {
                appendMessage("关闭选择器失败！");
            }
        }
        if (server != null && server.isOpen()) {
            try {
                server.close(); // 关闭服务器
            } catch (IOException e) {
                appendMessage("关闭服务器失败！");
            }
        }
        appendMessage("服务器已停止");
    }

    private void startServer() {
        try {
            selector = Selector.open();
            server = ServerSocketChannel.open();
            server.bind(new InetSocketAddress(8899));
            server.configureBlocking(false);
            server.register(selector, SelectionKey.OP_ACCEPT);
            JOptionPane.showMessageDialog(null, "服务器启动成功");
            String[] messages = messageController.getMessages();
            for (String str : messages) {
                appendMessage(str);
            }
            new Thread(() -> {
                while (flag) {
                    try {
                        if (selector.select() == 0) continue; // 阻塞直到有事件发生
                        Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                        while (iterator.hasNext()) {
                            SelectionKey key = iterator.next();
                            iterator.remove();
                            if (key.isAcceptable()) {
                                handleAccept(key);
                            }
                            if (key.isReadable()) {
                                handleRead(key);
                            }
                        }
                    } catch (IOException ex) {
                        if (flag) { // 只有在服务器运行时才处理异常
                            appendMessage("处理过程中发生错误！");
                        }
                    }
                }
                // 在线程退出前进行资源清理
                try {
                    if (selector != null) {
                        selector.close();
                    }
                } catch (IOException e) {
                    appendMessage("关闭选择器失败！");
                }
            }).start();
        } catch (IOException e) {
            AdministratorView.flag = false;
            frame.dispose();
        }
    }

    private void handleAccept(SelectionKey key) throws IOException {
        ServerSocketChannel server = (ServerSocketChannel) key.channel();
        SocketChannel client = server.accept();
        client.configureBlocking(false);
        client.register(selector, SelectionKey.OP_READ);
    }

    private void handleRead(SelectionKey key) throws IOException {
        SocketChannel client = (SocketChannel) key.channel();
        buffer.clear();  // 清空缓冲区
        int count;
        try {
            count = client.read(buffer);  // 读取数据到缓冲区
            if (count > 0) {
                buffer.flip();  // 切换到读模式
                String receivedMsg = charset.decode(buffer).toString();
                processMsg(receivedMsg, client); // 解码接收到的消息
            }
        } catch (IOException e) {
            // 客户端断开连接的异常处理
            client.close();  // 关闭客户端通道
            key.cancel();  // 取消对应的键
        }
    }

    private void processMsg(String msg, SocketChannel client) throws IOException {
        String seperator = ":";
        String[] ms = msg.split(seperator);
        if (ms.length == 1) {
            String s1 = " ";
            String[] ms1 = ms[0].split(s1);
            if (ms1.length == 2) {
                String msg1 = ms1[0];
                String msg2 = ms1[1];
                if (msg2.equals("上线了！")) {
                    onlineUsers.put(msg1, client);
                    updateUserList();
                }
            }
            appendMessage(msg);
            this.broadCast(msg);
        } else if (ms.length == 2) {
            appendMessage(msg);
            this.broadCast(msg);
            String ms1 = ms[0];
            String ms2 = ms[1];
            if (!ms2.equals("下线了")) {
                messageController.addMessage(ms1, ms2, 0);
            } else {
                onlineUsers.remove(ms1, onlineUsers.get(ms1));
                ChatClient.onlineUsers.put(ms1, false);
                updateUserList();
            }
        } else if (ms.length == 3) {
            String user_from = ms[0];
            String msg_body = ms[1];
            String user_to = ms[2];

            SocketChannel channel_to = onlineUsers.get(user_to);
            if (channel_to == null) {
                controller.addMessage(user_from, user_to, msg_body);
            } else {
                channel_to.write(charset.encode(user_from + ":" + msg_body + ":" + user_to));
                controller.addMessage(user_from, user_to, msg_body);
            }
            if (msg_body.equals("C") || msg_body.equals("D") || msg_body.equals("E")) {
                appendMessage(msg);
                broadCast(msg);
                messageController.addMessage(user_from, msg_body + ":" + user_to, 1);
            }
        } else if (ms.length == 4) {
            String ms1 = ms[0];
            String ms2 = ms[1];
            String ms3 = ms[2];
            String ms4 = ms[3];
            if (ms4.equals("1")) {
                broadCast(msg);
                appendMessage(msg);
                messageController.addMessage(ms1, ms2 + ":" + ms3, 1);
            }
            if (!ms4.equals("group")) {
                SocketChannel channel_to = onlineUsers.get(ms4);
                if (channel_to == null) {
                    controller.addMessage(ms1, ms4, ms2 + ":" + ms3);
                } else {
                    channel_to.write(charset.encode(ms1 + ":" + ms2 + ":" + ms3 + ":" + ms4));
                    controller.addMessage(ms1, ms4, ms2 + ":" + ms3);
                }
            } else {
                groupMessageController.addGroupMessage(ms3, ms2, ms1);
                groupBroadCast(msg, ms3);
            }
        } else if (ms.length == 5) {
            String ms1 = ms[0];
            String ms2 = ms[1];
            String ms3 = ms[2];
            String ms4 = ms[3];
            groupMessageController.addGroupMessage(ms4, ms2 + ":" + ms3, ms1);
            groupBroadCast(msg, ms4);
        }
    }

    private void sendMessage(String message) {
        if (!message.isEmpty()) {
            for (SocketChannel client : onlineUsers.values()) {
                try {
                    client.write(charset.encode("服务端" + ":" + message));
                    messageController.addMessage("服务端", message, 0);
                } catch (IOException e) {
                    appendMessage("发送消息失败");
                }
            }
            appendMessage("服务端：" + message);
        }
    }

    private void broadCast(String msg) throws IOException {
        Set<String> strings = onlineUsers.keySet();
        for (String string : strings) {
            SocketChannel client = onlineUsers.get(string);
            client.write(charset.encode(msg));
        }
    }

    private void groupBroadCast(String msg, String groupName) throws IOException {
        String[] groupUsers = groupChatController.getGroupUsers(groupName);
        for (String user : groupUsers) {
            if (user != null) {
                SocketChannel client = onlineUsers.get(user);
                if (client != null) {
                    client.write(charset.encode(msg));
                }
            }
        }
    }

    private void updateUserList() {
        SwingUtilities.invokeLater(() -> {
            listModel.clear();
            for (String user : onlineUsers.keySet()) {
                listModel.addElement(user);
            }
        });
    }

    private void updateGroupList() {
        SwingUtilities.invokeLater(() -> {
            groupModel.clear();
            for (String group : groupChatController.getAllGroupNames()) {
                groupModel.addElement(group);
            }
        });
    }

    private void updateFileList() {
        SwingUtilities.invokeLater(() -> {
            fileModel.clear();
            for (String fileName : messageController.getMessages()) {
                String[] ms = fileName.split(":");
                if (ms.length == 4) {
                    fileModel.addElement(ms[1] + ":" + ms[2]);
                }
            }
        });
    }

    private void appendMessage(String message) {
        SwingUtilities.invokeLater(() -> {
            StyledDocument doc = contentArea.getStyledDocument();

            Style boldStyle = doc.addStyle("bold", null);
            StyleConstants.setFontFamily(boldStyle, "宋体");
            StyleConstants.setFontSize(boldStyle, 15);
            StyleConstants.setBold(boldStyle, true);

            Style plainStyle = doc.addStyle("plain", null);
            StyleConstants.setFontFamily(plainStyle, "黑体");
            StyleConstants.setFontSize(plainStyle, 15);
            StyleConstants.setBold(plainStyle, false);
            StyleConstants.setForeground(plainStyle, Color.BLUE);

            String[] ms = message.split(":");
            try {
                if (ms.length == 2) {
                    String m2 = ms[1];
                    if (m2.equals("下线了")) {
                        return;
                    }
                }

                if (ms.length == 3) {
                    String ms1 = ms[0];
                    String ms2 = ms[1];
                    String ms3 = ms[2];
                    if (ms3.equals("0")) {
                        doc.insertString(doc.getLength(), ms1 + ":" + ms2 + "\n", boldStyle);
                    }
                    if (ms2.equals("C") || ms2.equals("D") || ms2.equals("E")) {
                        doc.insertString(doc.getLength(), ms1 + ":" + ms2 + ":" + ms3 + "\n", plainStyle);
                    }
                } else if (ms.length == 4) {
                    String ms1 = ms[0];
                    String ms2 = ms[1];
                    String ms3 = ms[2];
                    String ms4 = ms[3];
                    if (ms4.equals("1")) {
                        doc.insertString(doc.getLength(), ms1 + ":" + ms2 + ":" + ms3 + "\n", plainStyle);
                        links.put(ms2 + ":" + ms3, ms2 + ":" + ms3);
                    }
                } else {
                    String[] m = message.split(" ");
                    if (m.length == 2) {
                        String m2 = m[1];
                        if (m2.equals("上线了！")) {
                            return;
                        }
                    }
                    doc.insertString(doc.getLength(), message + "\n", boldStyle);
                }

                contentArea.setCaretPosition(doc.getLength());
            } catch (BadLocationException e) {
                System.out.println(e.getMessage());
            }
        });
    }

    private void openFile() {
        File file = new File(fileSelectedValue);
        if (file.exists()) {
            try {
                Desktop.getDesktop().open(file);
            } catch (IOException e) {
                JOptionPane.showMessageDialog(null, "文件打开失败");
            }
        } else {
            JOptionPane.showMessageDialog(frame, "文件不存在: " + file.getAbsolutePath());
        }
    }

    private void downLoad(String selectedValue) {
        try {
            if (onlineUsers.containsKey(selectedValue)) {
                SocketChannel client = onlineUsers.get(selectedValue);
                appendMessage(selectedValue + ":" + "下线了");
                broadCast(selectedValue + ":" + "下线了");
                ChatClient.onlineUsers.put(selectedValue, false);
                onlineUsers.remove(selectedValue, client);
                updateUserList();
                client.close();
            }
        } catch (IOException e) {
            appendMessage("强制下线失败");
        }
    }

    // 查找被点击的链接文本
    private static String findClickedLink(JTextComponent textComponent, Point point) throws BadLocationException {
        // 遍历所有的链接文本
        for (String linkText : links.keySet()) {
            // 获取当前链接文本在文本组件中的起始位置
            int start = textComponent.getDocument().getText(0, textComponent.getDocument().getLength()).indexOf(linkText);

            // 如果找到了链接文本
            if (start != -1) {
                // 获取链接文本的起始和结束矩形区域
                Rectangle startRect = textComponent.modelToView(start);
                Rectangle endRect = textComponent.modelToView(start + linkText.length());

                // 确保矩形区域有效
                if (startRect != null && endRect != null) {
                    // 合并起始和结束矩形区域，得到整个链接的矩形区域
                    Rectangle linkRect = startRect.union(endRect);

                    // 检查点击点是否在链接矩形区域内
                    if (linkRect.contains(point)) {
                        return linkText; // 返回被点击的链接文本
                    }
                }
            }
        }
        // 如果没有找到被点击的链接，返回 null
        return null;
    }

    public static void main(String[] args) {
        new ChatServer();
    }
}